package com.gdth.core.dao;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.Date;
import java.util.ArrayList;
import java.util.List;

import com.gdth.core.annotation.table.Column;
import com.gdth.core.annotation.table.Id;
import com.gdth.core.annotation.table.Table;
import com.gdth.core.db.SqliteDbHelper;
import com.gdth.utils.ClassUtil;
import com.gdth.utils.SqlUtil;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

/**
 * 
 * @author Arvin
 *
 * @param <T>
 */
public class BaseDaoImpl<T> implements BaseDao<T>{
	private Context mContext;
	private String tableName;
	private String idColumn;
	private Class<T> mClass;
	private List<Field> Fields;
	
	private int[] fieldPostion;
	
	@SuppressWarnings("unchecked")
	public BaseDaoImpl(Context mContext) {
		// TODO Auto-generated method stub
		this.mContext = mContext;
		this.mClass = ((Class<T>) ((ParameterizedType) super.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
	
		if (this.mClass.isAnnotationPresent(Table.class)){
			Table mTable = (Table) this.mClass.getAnnotation(Table.class);
			
			this.tableName = mTable.name();
		}
		
		this.Fields = ClassUtil.getFields(mClass.getDeclaredFields(), mClass.getSuperclass().getDeclaredFields());
		
		this.idColumn = ClassUtil.getPrimaryKeyByFields(this.Fields);
		
		if (!isExit())
			CreateTable();
		
		this.fieldPostion = initFieldPostion();
		
		
	}
	
	/**
	 * ����һ������
	 */
	@Override
	public long insert(T entity) {
		// TODO Auto-generated method stub
		long success = 1;
		SQLiteDatabase db = SqliteDbHelper.getIntance(mContext).getWritableDatabase();
		
		db.beginTransaction();
		try{
			ContentValues cv = new ContentValues();
			
			setContentValues(entity, cv, "create");
			
			db.insert(this.tableName, null, cv);
			
			db.setTransactionSuccessful();
		}
		catch(Exception e){
			e.printStackTrace();
			success = 0;
		}
		finally{
			db.endTransaction();
			db.close();
		}
		
		return success;
	}
	
	/**
	 * �����������
	 */
	@Override
	public long insert(List<T> entitys){
		long success = 1;
		SQLiteDatabase db = SqliteDbHelper.getIntance(mContext).getWritableDatabase();
		
		db.beginTransaction();
		try{
			for (T entity : entitys){
				ContentValues cv = new ContentValues();
			
				setContentValues(entity, cv, "create");
			
				db.insert(this.tableName, null, cv);
			}
			
			db.setTransactionSuccessful();
		}
		catch(Exception e){
			e.printStackTrace();
			success = 0;
		}
		finally{
			db.endTransaction();
			db.close();
		}
		
		return success;
	}

	@Override
	public void delete(int id) {
		// TODO Auto-generated method stub
		SQLiteDatabase db = SqliteDbHelper.getIntance(mContext).getWritableDatabase();
		
		db.beginTransaction();
		
		try{
			db.execSQL("DELETE FROM " + this.tableName + " WHERE id = ? ",  
					new String[] { String.valueOf(id) });  
			db.setTransactionSuccessful();
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			db.endTransaction();
			db.close();
		}
	}

	@Override
	public void delete(Integer... ids) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void update(T entity) {
		// TODO Auto-generated method stub
		SQLiteDatabase db = SqliteDbHelper.getIntance(mContext).getWritableDatabase();
		
		db.beginTransaction();
		
		try{
//			db.execSQL("UPDATE " + this.tableName
//					+ "SET data = ? WHERE id = ?",
//					new Object[] { this.dbHelper.objectToBytes(entity),
//					this.idColumn });  

			db.setTransactionSuccessful();
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			db.endTransaction();
			db.close();
		}
	}

	@Override
	public T get(int id) {
		// TODO Auto-generated method stub
		String selection = this.idColumn + " = ?";
		
		String[] str = {Integer.toString(id)};
		
		List<T> list = fing(null, selection, str, null, null, null, null);
		
		if (list != null && list.size() > 0){
			return (T)list.get(0);
		}
		return null;
	}

	@Override
	public List<T> rawQuery(String sql, String[] arg0) {
		// TODO ���ҵ���ʵ��
		List<T> mList = new ArrayList<T>();
		
		SQLiteDatabase db = SqliteDbHelper.getIntance(mContext).getReadableDatabase();
		Cursor cursor = null;
		try{
			cursor = db.rawQuery(sql, arg0);
			while(cursor.moveToNext()){
				mList.add(getEntityFromCursor(cursor));
			}
		}catch(Exception e){
			
		}finally{
			if (cursor != null)
				cursor.close();
			
			db.close();
		}
		return null;
	}

	@Override
	public List<T> find() {
		// TODO Auto-generated method stub
		List<T> mList = new ArrayList<T>();
		SQLiteDatabase db = SqliteDbHelper.getIntance(mContext).getReadableDatabase();
		Cursor cursor = null;
		try{
			cursor = db.rawQuery("select * from " + tableName + " limit ?, ?",   
                new String[]{String.valueOf(0), String.valueOf(10)});  
			
	        while(cursor.moveToNext()){  
	        	mList.add(getEntityFromCursor(cursor));  
	        }  
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if (cursor != null){
				cursor.close();
			}
			db.close();
		}

		return mList;
	}

	@Override
	public List<T> fing(String[] arg0, String arg1, String[] arg2, String arg3,
			String arg4, String arg5, String arg6) {
		// TODO �������ݣ�����list
		List<T> mList = new ArrayList<T>();
		SQLiteDatabase db = SqliteDbHelper.getIntance(mContext).getReadableDatabase();
		Cursor cursor = null;
		try{
			cursor = db.rawQuery("select * from " + tableName + " limit ?, ?",   
                new String[]{String.valueOf(0), String.valueOf(10)});  
			
	        while(cursor.moveToNext()){  
	        	mList.add(getEntityFromCursor(cursor));  
	        }  
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if (cursor != null){
				cursor.close();
			}
			db.close();
		}
		return null;
	}

	@Override
	public boolean isExist(String sql, String[] arg0) {
		// TODO �ж������Ƿ����
		boolean result = false;
		Cursor cursor = null;
        try {
            cursor = SqliteDbHelper.getIntance(mContext).getReadableDatabase().rawQuery(sql, arg0);
            if(cursor.moveToNext()){
                int count = cursor.getInt(0);
                if(count > 0){
                    result = true;
                }
            }
        } catch (Exception e) {
            // TODO: handle exception
        	e.printStackTrace();
        }finally{
        	if (cursor != null){
        		cursor.close();
        		SqliteDbHelper.getIntance(mContext).getReadableDatabase().close();
        	}
        }
		return result;
	}

	@Override
	public void execSql(String sql, Object[] agr0) {
		// TODO Auto-generated method stub
		
	}
	
	/**************************���÷���*******************************/
	/**
	 * ��ֵ��ContentValues
	 * @param entity
	 * @param cv
	 * @param type
	 */
	private void setContentValues(T entity, ContentValues cv, String type){
        // TODO: ContentValues��ֵ
		for(Field field : this.Fields){
			if(!field.isAnnotationPresent(Column.class)){
				continue;
			}
			
			Column mColumn = field.getAnnotation(Column.class);
			
			field.setAccessible(true);
			
			Object fieldValue = null;
			try {
				fieldValue = field.get(entity);
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			//ֵΪ��ʱ������
			if (fieldValue == null)
				continue;
			
			//ֵΪ��������ʱ������
			if ("create".equals(type) && field.isAnnotationPresent(Id.class)){
				continue;
			}
			
			//ʱ������ת��Ϊʱ��
			if (Date.class == field.getType()){
				cv.put(mColumn.name(), ((Date) fieldValue).getTime());
				continue;
			}
			
			//Ĭ��ֵΪString
			cv.put(mColumn.name(), fieldValue.toString());
		}
	}
	
	/**
	 * ������
	 * @param db
	 * @return
	 */
	private boolean CreateTable(){
        // TODO: ������
		boolean result = false;
		Cursor cursor = null;
		SQLiteDatabase db = SqliteDbHelper.getIntance(mContext).getWritableDatabase();
        try {
        	String sql = SqlUtil.createTable(mClass);
        	db.execSQL(sql);
        	result = true;
        }catch(Exception e){
        	e.printStackTrace();
        }finally{
        	if (cursor != null){
        		cursor.close();
        		db.close();
        	}
        }
		return result;
	}
	
	/**
	 * �жϱ��Ƿ����
	 * @param db
	 * @return
	 */
	private boolean isExit(){
        // TODO: �жϱ��Ƿ����
		boolean result = false;
		
		String sql = SqlUtil.isExistTable(mClass);
		
		SQLiteDatabase db = SqliteDbHelper.getIntance(mContext).getReadableDatabase();
		Cursor cursor = null;
        try {
            cursor = db.rawQuery(sql, null);
            if(cursor.moveToNext()){
                int count = cursor.getInt(0);
                if(count>0){
                    result = true;
                }
            }
                 
        } catch (Exception e) {
        	
        }finally{
        	if (cursor != null){
        		cursor.close();
        		db.close();
        	}
        }

		return result;
	}

	public T getEntityFromCursor(Cursor cursor){   
        int length = Fields.size();  
          
        T entity = null;  
        String db_data;  
        String fieldTypeName; 
        String fieldName;
        
        try {  
            entity = this.mClass.newInstance();  
            for(int i=0; i<length; i++){  
                Field mField = this.Fields.get(i);
                fieldTypeName = mField.getType().toString();
                fieldName = mField.getName();
                db_data = cursor.getString(fieldPostion[i]);  
                if(null != db_data){  
                	if("class java.lang.Integer".equals(fieldTypeName))
                		ClassUtil.setFieldValue(entity, fieldName, Integer.parseInt(db_data));
                    else if("int".equals(fieldTypeName)) 
                    	ClassUtil.setFieldValue(entity, fieldName, Integer.parseInt(db_data)); 
                	else if("class java.lang.Short".equals(fieldTypeName))
                		ClassUtil.setFieldValue(entity, fieldName, Short.parseShort(db_data));
                	else if("class java.lang.Double".equals(fieldTypeName))
                		ClassUtil.setFieldValue(entity, fieldName, Double.parseDouble(db_data));
                	else if("class java.lang.Boolean".equals(fieldTypeName))
                		ClassUtil.setFieldValue(entity, fieldName, Boolean.parseBoolean(db_data));
                	else if("class java.lang.String".equals(fieldTypeName))
                        ClassUtil.setFieldValue(entity, fieldName, db_data);   
                    else if("long".equals(fieldTypeName))  
                    	ClassUtil.setFieldValue(entity, fieldName, Long.getLong(db_data)); 
                    else if("float".equals(fieldTypeName))
                    	ClassUtil.setFieldValue(entity, fieldName,Float.parseFloat(db_data));  
                	
                    else if("class java.util.Date".equals(fieldTypeName))
                		ClassUtil.setFieldValue(entity, fieldName, Date.valueOf(db_data));
                }  
            }  
        } catch (Exception e) {  
//            System.out.println(e.getMessage());  
        }  
        return entity;  
    }  
	
	protected int[] initFieldPostion(){    
        int length = this.Fields.size();  
        
        int[] postion = new int[length];  
        
        Cursor cursor = SqliteDbHelper.getIntance(mContext).getReadableDatabase().rawQuery("select * from " + tableName + " limit ?, ?", new String[]{"0", "2"});  
        for(int i = 0; i < length; i++){  
            postion[i] = cursor.getColumnIndex(this.Fields.get(i).getName());  
        }  
          
        return postion;  
    }  

}
